#!/usr/bin/perl -w

#---------------------------------------------------------------------------
# PROGRAM : BlastJobs.pl
# PURPOSE : Produce .csh files for executing blastAll on a set of sequences.
# AUTHOR  : Jessica Kissinger and Jonathan Myers
# CREATED : May 28, 2002
# MODIFIED: Jamie Estill, Sept 2, 2004
# HISTORY : 
#          Jamie Estill, Sept 2, 3004
#           * Modified commmands that print *.csh files to allow for quotes
#             around the database name so that multiple databases may be used
#           * Added usage example 2 for multiple databases 
#          Jamie Estill, Sept 1, 2004
#           * Added usage example 1
#          Jamie Estill, July 23, 2004
#           * Added -a 2 switch in $args for ncbi blast to work on two processors
#           * modified the readdir comman to ignore the . and ..
#           * Added -m e switch to the qsub command to have an email sent to 
#             the user when the job terminates
# USAGE   : ncbi_blast.pl -o <outputDir> -d <database>
#			  -i <baseDir> -j <numberOfJobs>
#                        -p <program> -t <time requested, in minutes)
#
# EXAMPLES: (1) ./ncbi_blast.pl -d /guest/jestill/db/RiceTIGR2.cds -i /guest/jestill/input 
#                -p blastn -t 1000000 -o /scratch/jestill/output -j 8
#
#           (2) ./ncbi_blast.pl -d "/guest/jestill/db/Embryophyta.fasta /guest/jestill/db/Embryophtya_A.fastsa"
#              -i /guest/jestill/input -p blastn -t 1000000 -o /scratch/jestill/output -j 8
#
#
# COMMENTS:
#     This program is designed to run blast jobs on the Kissinger/CTEGD
#     Linux cluster.  This particular program runs NCBI Blast, but can be 
#     modified for other programs. The user must specify 5 arguments to the
#     program: the blast program (-p), the database to be searched (-d),
#     the location of the individual fasta formatted files to be used for
#     the search (-i), the location where the individual blast results are 
#     to be stored (-o), the number of processors to be used (-j), and the
#     amount of time requested (-t) in minutes.
#
#     In a nutshell, this program will create a list of all the files in
#     the input directory (the files to be blasted) and then generate a
#     a unix system call to perform the specified Blast search of the 
#     specified database.  These system call arguments will be saved as
#     shell scripts.  There will be one shell script created for each
#     job (node) specified.  The shell scripts will consist of subsets of 
#     the system calls, e.g. 1000 files to blast on 10 nodes will generate
#     10 shell scripts of 100 system calls each.
#  
#     Finally, the shell scripts themselves are launched on the cluster
#     by issuing a "bsubmit" command which specifies the number of nodes,
#     the amount of time reqested and the location of the shell scripts.
#
#     If you need to pass arguments to Blast, it is easiest to hard code
#     them in the script below by specifying $args
#
#     Note, this script not only makes the files, it runs them. If there is 
#     a formatting mistake in the system calls then the jobs will not run
#     properly and will need to be deleted.  You may want to comment out the 
#     sub "execute" the first time around and have a look at the shell scripts
#     before running them.
#---------------------------------------------------------------------------

my $blastPath ="/opt/NCBI_BLAST"; #change path as necessary

use strict;

# The following are default settings for the command line variables

my $database = '';
my $output = '';
my $basePath = '';
my $numJobs = '';
my $time = '';
my $program = '';
my $args = '-a 2';  # ARGUMENTS
                    # -a 2  : Use two processors
                    # specify arguments here if needed, e.g. -b 20 -v 20


##### MAIN #####

# check if the parameters were provided
if (@ARGV < 6) {
  print "usage: ncbi_blast.pl -d <database>".
      " -i <input directory> -p <program> -t <time>".
      " -o <output directory>".
      " -j <number of jobs/nodes as an integer i.e. 8> \n";
  die;
}

#parse in the variables
setCommandVariables();

#specify the BLAST command
my $command = "$blastPath/blastall"; #change as necessary,

#read in names of files to be blasted
opendir( DIR, $basePath );                          # Open the directory supplied as basePath by the user
  # my @fileList = readdir( DIR );                  # The readdir command as originally written
  my @fileList = grep !/^\.\.?$/, readdir DIR ;     # Read the directory ignoring the . and ..
closedir( DIR );                                    # Close the directory
 
# make a directory for the output file unless already exists
mkdir $output, 0777 unless (-e $output); # set permissions

my $i = 1;
my $first = 1;

#write out the system calls in the shell script files
foreach my $file ( @fileList ){

	if( $first == 0 ){

		open( OUT, ">> $output/jobs$i.csh");
                print OUT $command," -p $program -i $basePath/$file -d \"$database\" -o  $output/$file.$program $args\n"; 
                # Changed the below to the above to allow Quotations around database name for multiple databases
		#print OUT $command," -p $program -i $basePath/$file -d $database -o  $output/$file.$program $args\n";
		close( OUT );
	}
	else{
	    
		open( OUT, "> $output/jobs$i.csh");
                print OUT $command," -p $program -i $basePath/$file -d \"$database\" -o  $output/$file.$program $args\n";
		#print OUT $command," -p $program -i $basePath/$file -d $database -o  $output/$file.$program $args\n";
		close( OUT );
	}

	$i++;
	if( $i > $numJobs )
        {
		$i = 1;
		$first = 0;
	}
}

#make the shell scripts executable
qx/chmod +x $output\/jobs*.csh/;

#run the shell scripts
executeJobs( ); #comment out this line if you don't want to run now

print "DONE\n";

exit;

##### SUBRUTINES #####

sub setCommandVariables {

        for( my $i = 0; $i < @ARGV; $i++ ){
                        
                my $var = $ARGV[$i];
                
                if( $var eq '-i' ){

                        $i++;
                        $basePath = $ARGV[$i];
                }
                elsif( $var eq '-d' ){

                        $i++;
                        $database = $ARGV[$i];
                }
                elsif( $var eq '-o' ){

                        $i++;
                        $output = $ARGV[$i];
                }
                elsif( $var eq '-j' ){
        
                        $i++;   
                        $numJobs = $ARGV[$i];
                }   
		 elsif( $var eq '-p' ){
        
                        $i++;   
                        $program = $ARGV[$i];
                }   
		 elsif( $var eq '-t' ){
        
                        $i++;   
                        $time = $ARGV[$i];
                }   
        }
}                

sub executeJobs {

	opendir( DIR, "$output" );
	my @list = readdir( DIR );
	closedir( DIR );

	foreach my $elm ( @list ){

		if( $elm =~ /.*\.csh$/ ){
		        
		        # Original code from Kissinger lab script
			#open( PROC, "|qsub -l nodes=1:compute,walltime=$time $output/$elm" );
                        # Options added by jamie to the qsub
		        # -m e : mail when the submitted jobs is completed, this will send an email for each of the qsubs
			open( PROC, "|qsub -l nodes=1:compute,walltime=$time $output/$elm -m e" );
			print PROC<<"EOF";
EOF
			close( PROC );
		}
	}
}
